﻿using System;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web.Mvc;

using AMC.SubstitutionCache.Filters;

using Orchard;
using Orchard.Mvc.Html;

namespace AMC.SubstitutionCache.Services
{

    public interface IAntiForgeryTokenService : IDependency
    {
        string ReplaceTokensWithBeacons(string input);
        string ReplaceBeaconsWithTokens(ActionExecutingContext context, string input);
    }

    public interface IAntiForgeryTokenValueProvider : IDependency
    {
        MvcHtmlString GetValue(ControllerContext context);
    }

    public class AntiForgeryTokenService: IAntiForgeryTokenService
    {
        private IAntiForgeryTokenValueProvider _valueProvider;

        public AntiForgeryTokenService(IAntiForgeryTokenValueProvider valueProvider)
        {
            _valueProvider = valueProvider;
        }
        private const string AntiforgeryBeacon = "<!--OutputCacheFilterAntiForgeryToken-->";
        private const string AntiforgeryTag = "<input name=\"__RequestVerificationToken\" type=\"hidden\" value=\"";
        
        public string ReplaceTokensWithBeacons(string input)
        {
            var tokenIndex = input.IndexOf(AntiforgeryTag, StringComparison.Ordinal);

            // substitute antiforgery token by a beacon
            if (tokenIndex != -1)
            {
                var sb = new StringBuilder();
                var previousTokenEnd = 0;

                while (tokenIndex != -1)
                {
                    sb.Append(input.Substring(previousTokenEnd, tokenIndex - previousTokenEnd));
                    sb.Append(AntiforgeryBeacon);

                    previousTokenEnd = input.IndexOf(">", tokenIndex, StringComparison.Ordinal) + 1;

                    tokenIndex = input.IndexOf(AntiforgeryTag, previousTokenEnd, StringComparison.Ordinal);
                }

                sb.Append(input.Substring(previousTokenEnd));
                return sb.ToString();
            }

            return input;
        }

        public string ReplaceBeaconsWithTokens(ActionExecutingContext context, string input)
        {
            // replace any anti forgery token with a fresh value
            if (input.Contains(AntiforgeryBeacon))
            {
                var token = _valueProvider.GetValue(context);

                return input.Replace(AntiforgeryBeacon, token.ToString());
            }

            return input;
        }
    }

    public class AntiForgeryTokenValueProvider : IAntiForgeryTokenValueProvider
    {
        public MvcHtmlString GetValue(ControllerContext context)
        {
            var viewContext = new ViewContext
            {
                HttpContext = context.HttpContext,
                Controller = context.Controller
            };

            var htmlHelper = new HtmlHelper(viewContext, new ViewDataContainer());

            return htmlHelper.AntiForgeryTokenOrchard();
        }
    }
}